package net.oschina.archx.spring.sequoiadb.utils;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SequoiaSQLHelper
 *
 * @author Archx
 * @date 2015/6/30 0030
 */
public abstract class SequoiaSQLHelper {

    /**
     * #{name} 匹配正则
     */
    private static final Pattern M_PATTERN = Pattern.compile("#\\{(\\w+)\\}");

    /**
     * ? 匹配正则
     */
    private static final Pattern P_PATTERN = Pattern.compile("\\?");

    /**
     * 引号
     */
    private static final String QUOTE_STR = "\"";

    private static final String NULL_STR = "null";

    /**
     * 准备语句
     *
     * @param sql    原始语句
     * @param params 参数
     * @return sql
     */
    public static final String preparedStatement(String sql, Object... params) {
        if (StringUtils.isEmpty(sql))
            throw new IllegalArgumentException("sql 语句不能为 NULL.");
        if (params != null && params.length == 1) {
            return handleOnlyParameter(sql, params[0]);
        } else {
            if (params != null && params.length > 1)
                return handleArrayParameters(sql, params);
            else
                return sql;
        }


    }

    static final String handleOnlyParameter(String sql, Object param) {
        Class<?> clazz = param.getClass();
        // 集合处理
        if (param instanceof Collection) {
            Collection<?> coll = (Collection<?>) param;
            if (!coll.isEmpty() && coll.size() > 0)
                return handleArrayParameters(sql, coll.toArray());
        }

        StringBuffer sb = new StringBuffer();
        Matcher matcher = M_PATTERN.matcher(sql);

        if (param instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) param;
            while (matcher.find()) {
                String key = matcher.group(1);
                Object value = map.get(key);
                matcher.appendReplacement(sb, handleParam(value, value == null ? Object.class : value.getClass()));
            }
            matcher.appendTail(sb);
        } else if (param instanceof String || isWrapper(clazz) || clazz.isPrimitive()) {
            while (matcher.find()) {
                matcher.appendReplacement(sb, handleParam(param, clazz));
            }
            matcher.appendTail(sb);
        } else if (!isJavaClass(clazz) && !clazz.isInterface()) {
            while (matcher.find()) {
                String name = matcher.group(1);
                Field field = ReflectionUtils.findField(clazz, name);
                ReflectionUtils.makeAccessible(field);
                Object value = ReflectionUtils.getField(field, param);
                matcher.appendReplacement(sb, handleParam(value, field.getType()));
            }
            matcher.appendTail(sb);
        }
        return sb.length() > 0 ? sb.toString() : sql;
    }

    /**
     * 处理数组类型的参数
     *
     * @param sql    原始语句
     * @param params 参数数组
     * @return sql
     */
    static final String handleArrayParameters(String sql, Object[] params) {
        StringBuffer sb = new StringBuffer();
        int bounds = params.length;
        int count = 0;

        Matcher matcher = P_PATTERN.matcher(sql);
        while (matcher.find()) {
            int index = count++;
            if (index > bounds - 1)
                matcher.appendReplacement(sb, NULL_STR);
            else {
                Object param = params[index];
                Class<?> clazz = param.getClass();
                if (isWrapper(clazz) || clazz.isPrimitive() || clazz == String.class)
                    matcher.appendReplacement(sb, handleParam(param, clazz));
                else
                    throw new IllegalArgumentException("仅支持字符串(java.lang.String) 和 原始数据类型及其包装类!");
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 处理参数
     *
     * @param param 参数
     * @param clazz 参数类型
     * @return value
     */
    static final String handleParam(Object param, Class<?> clazz) {
        if (param == null)
            return NULL_STR;
        // 字符串类型添加引号
        if (param instanceof String || clazz == Character.class || clazz == char.class) {
            return QUOTE_STR + param.toString() + QUOTE_STR;
        }
        return param.toString();
    }

    public static final boolean isWrapper(Class<?> target) {
        try {
            return ((Class<?>) target.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }

    public static final boolean isJavaClass(Class<?> target) {
        return target != null && target.getClassLoader() == null;
    }
}
